/*
在747929791的基础上改动，
希望可以做出一个“体面的”AI
*/

#include "sdk/sdk.h"
#include "sdk/misc.h"
#include "sdk/const.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <set>
#include <ctime>
#include <algorithm>
using namespace std;

using Pos = SDK::Pos;
using PPlayerInfo = SDK::PPlayerInfo;
using PCommand = SDK::PCommand;
using PShowInfo = SDK::PShowInfo;
using Edge = PPlayerInfo::Edge;
using Robot = PPlayerInfo::Robot;
using HumanOrder = PPlayerInfo::HumanOrder;
using Buff = Robot::Buff;
using Skill = Robot::Skill;
using Operation = PCommand::Operation;
using ShowInfo = PShowInfo::ShowInfo;

PPlayerInfo playerInfo;
PCommand pCommand;
PShowInfo *pShowInfo;

namespace DecentAI0
{

//主过程，通过playerInfo得到pCommand
void solve()
{
	//清空要输出的指令
	pCommand.cmds.clear();

	vector<Robot *> myRobot, enemyRobot;//我方机器人列表，敌方机器人列表
	vector<Pos> buildablePos;//当前地图上的空地
	vector<Pos> occupied;//已经被占据的位置
	set<pair<Pos, Pos> > links;
	for(Edge e: playerInfo.edges)
		if(!e.LeftTime)
			links.insert(make_pair(e.source, e.target));
	for (unsigned int i = 0; i < playerInfo.robots.size(); i++)
	{
		Robot& obj = playerInfo.robots[i];
		occupied.push_back(obj.pos);
		if (obj.team == playerInfo.team)
			myRobot.push_back(&obj);
		else
			enemyRobot.push_back(&obj);
	}

	for (int x = 0; x < MAP_SIZE; x++)
		for (int y = 0; y < MAP_SIZE; y++)
			if (MAP[x][y] == 1 && playerInfo.RobotAt(Pos(x, y)) == NULL)
				buildablePos.push_back(Pos(x, y));
	//我方、敌方：均按hp百分比排序，低的排在前面
	auto cmpHp = [](const Robot *l, const Robot *r){return l->hp * r->max_hp < r->hp * l->max_hp;};
	sort(myRobot.begin(), myRobot.end(), cmpHp);
	sort(enemyRobot.begin(), enemyRobot.end(), cmpHp);
	//空位置：排序
	double sa[MAP_SIZE][MAP_SIZE];
	for(int i = 0; i < MAP_SIZE; ++i)
		for(int j = 0; j < MAP_SIZE; ++j)
		{
			sa[i][j] = 0;
			for(int ti = 0; ti < MAP_SIZE; ++ti)
				for(int tj = 0; tj < MAP_SIZE; ++tj)
					if((i - ti) * (i - ti) + (j - tj) * (j - tj) <= GatherRange)
						sa[i][j] += ENERGY[ti][tj];
		}
	auto value = [&occupied, &sa](Pos pos) -> double
	{
		int ans = 1 << 30;
		for(Pos q: occupied)
			ans = min(ans, pos.dist2(q));
		return ans * sa[pos.x][pos.y];
	};
	auto cmpEmpty = [value](Pos l, Pos r){return value(l) > value(r);};
	sort(buildablePos.begin(), buildablePos.end(), cmpEmpty);
	
	//weight：每个机器人需要能量的权重；need：每个机器人用来放本回合技能的消耗
	map<Pos, int> weight, need;
	
	//思路：计算每个机器人在“前方”还是“后方”，存储到三个vector中
	vector<Robot *> myFront, myMiddle, myBack;
	//前方：能攻击到敌人或能被敌人攻击
	//同时计算每个机器人的weight
	for(Robot *my: myRobot)
	{
		weight[my->pos] = 1;
		int curWeight = 0;
		for(Robot *ene: enemyRobot)
		{
			int dist = my->pos.dist2(ene->pos);
			if(dist <= my->attack_range || dist <= ene->attack_range)
				++curWeight;
		}
		if(curWeight)
		{
			myFront.push_back(my);
			weight[my->pos] += curWeight;
		}
	}
	//中间：与最近的“前方”距离不超过10
	for(Robot *my: myRobot)
		//首先本身不能是“前方”
		if(find(myFront.begin(), myFront.end(), my) == myFront.end())
			//再从“前方”中枚举，判断距离
			for(Robot *fr: myFront)
				if(my->pos.dist2(fr->pos) <= 10)
				{
					myMiddle.push_back(my);
					break;
				}
	//后方：剩下的
	for(Robot *my: myRobot)
		if(find(myFront.begin(), myFront.end(), my) == myFront.end())
			if(find(myMiddle.begin(), myMiddle.end(), my) == myMiddle.end())
				myBack.push_back(my);
	//对于我方的每个机器人，对其分配操作
	for(auto my: myRobot)
	{
		//尝试攻击，这里会优先考虑脆弱的敌人
		Pos target = Pos(-1, -1);
		for(auto ene: enemyRobot)
			if(my->pos.dist2(ene->pos) <= my->attack_range)
			{
				pCommand.AddOrder(PlainAttack, my->pos, target = ene->pos);
				break;
			}
		//感觉自己的能量比较多，可以放技能啦！
		if(my->energy >= my->consumption)
		{
			// printf("want use skill\n");
			int freeEnergy = my->energy - my->consumption;
			//我在前方，那我最好是攻击型
			if(find(myFront.begin(), myFront.end(), my) != myFront.end())
			{
				// printf("front skill %d %d\n", my->pos.x, my->pos.y);
				//听说天灾比较强，优先用天灾
				if(my->canUse(ScourgeSkill) && target != Pos(-1, -1)
					&& freeEnergy >= Skill::Cost(ScourgeSkill, my->level, my->type))
				{
					pCommand.AddOrder(Scourge, my->pos, target);
					need[my->pos] += Skill::Cost(ScourgeSkill, my->level, my->type);
					goto usedSkill;
				}
				//没有天灾，轰炸也行呀
				if(my->canUse(BombingSkill) && target != Pos(-1, -1)
					&& freeEnergy >= Skill::Cost(BombingSkill, my->level, my->type))
				{
					pCommand.AddOrder(Bombing, my->pos, target);
					need[my->pos] += Skill::Cost(BombingSkill, my->level, my->type);
					goto usedSkill;
				}
				// printf("free %d cost %d\n", freeEnergy, Skill::Cost(EvolveSkill, my->level, my->type));
				//上面两个都用不了，考虑别的技能
				//如果我是攻击型（或啥都不是），我就想进化
				if((my->type == AttackRobot || my->type == RawRobot || my->level <= 1) && my->canUse(EvolveSkill)
					&& freeEnergy >= Skill::Cost(EvolveSkill, my->level, my->type))
				{
					pCommand.AddOrder(Evolve, my->pos, my->type == RawRobot ? AttackRobot : my->type);
					need[my->pos] += Skill::Cost(EvolveSkill, my->level, my->type);
					goto usedSkill;
				}
				//如果我是其他类型，我就想变成攻击型
				if(my->type != AttackRobot && my->type != RawRobot && my->canUse(VestigialSkill)
					&& freeEnergy >= Skill::Cost(VestigialSkill, my->level, my->type))
				{
					pCommand.AddOrder(Vestigial, my->pos, AttackRobot);
					goto usedSkill;
				}
				//没什么重大技能要用了，可以没事做一点连接
				if(my->canUse(ConnectSkill) && freeEnergy >= Skill::Cost(ConnectSkill, my->level, my->type))
				{
					//先寻找连接目标，但是只在“前方”范围内找
					//并且，优先连接较强壮的友方
					for(auto target: myFront)
						if(my->pos.dist2(target->pos) <= SplitRange && !links.count(make_pair(my->pos, target->pos)))
						{
							pCommand.AddOrder(Connect, my->pos, target->pos);
							need[my->pos] += Skill::Cost(ConnectSkill, my->level, my->type);
							goto usedSkill;
						}
				}
				// printf("front use fail\n");
			}
			//我在中间，那我最好是防御型
			else if(find(myMiddle.begin(), myMiddle.end(), my) != myMiddle.end())
			{
				// printf("middle skill %d %d\n", my->pos.x, my->pos.y);
				//听说庇护比较强，优先用这个啦
				if(my->canUse(ShieldingSkill) && freeEnergy >= Skill::Cost(ShieldingSkill, my->level, my->type))
				{
					pCommand.AddOrder(Shielding, my->pos, target);
					need[my->pos] += Skill::Cost(ShieldingSkill, my->level, my->type);
					goto usedSkill;
				}
				//没事可以回个血
				if(my->canUse(RecoverSkill) && freeEnergy >= Skill::Cost(RecoverSkill, my->level, my->type))
				{
					vector<const Robot *> targets;
					//先寻找回血目标
					for(Edge e: playerInfo.edges)
						if(e.source == my->pos && !e.LeftTime)
							targets.push_back(playerInfo.RobotAt(e.target));
					//找到最脆弱的目标
					if(!targets.empty())
					{
						sort(targets.begin(), targets.end(), cmpHp);
						pCommand.AddOrder(Recover, my->pos, targets.front()->pos);
						need[my->pos] += Skill::Cost(RecoverSkill, my->level, my->type);
						goto usedSkill;
					}
				}
				//如果我是防御型（或啥都不是），我就想进化
				if((my->type == DefenseRobot || my->type == RawRobot || my->level <= 1) && my->canUse(EvolveSkill)
					&& freeEnergy >= Skill::Cost(EvolveSkill, my->level, my->type))
				{
					pCommand.AddOrder(Evolve, my->pos, my->type == RawRobot ? DefenseRobot : my->type);
					need[my->pos] += Skill::Cost(EvolveSkill, my->level, my->type);
					goto usedSkill;
				}
				//如果我是其他类型，我就想变成防御型
				if(my->type != DefenseRobot && my->type != RawRobot && my->canUse(VestigialSkill)
					&& freeEnergy >= Skill::Cost(VestigialSkill, my->level, my->type))
				{
					pCommand.AddOrder(Vestigial, my->pos, DefenseRobot);
					need[my->pos] += Skill::Cost(VestigialSkill, my->level, my->type);
					goto usedSkill;
				}
				//没什么重大技能要用了，可以没事做一点连接
				if(my->canUse(ConnectSkill) && freeEnergy >= Skill::Cost(ConnectSkill, my->level, my->type))
				{
					//先寻找连接目标，优先连前方，然后中间，最后后方
					//并且，优先连接较强壮的友方
					vector<const Robot *> targets;
					targets.insert(targets.end(), myFront.rbegin(), myFront.rend());
					targets.insert(targets.end(), myMiddle.rbegin(), myMiddle.rend());
					targets.insert(targets.end(), myBack.rbegin(), myBack.rend());
					for(auto target: targets)
						if(my->pos.dist2(target->pos) <= SplitRange && !links.count(make_pair(my->pos, target->pos)))
						{
							pCommand.AddOrder(Connect, my->pos, target->pos);
							need[my->pos] += Skill::Cost(ConnectSkill, my->level, my->type);
							goto usedSkill;
						}
				}
				//这里不进行传输，因为可以使用AutoTransfer函数
			}
			//我在后方，那我最好是采集型
			else
			{
				// printf("back skill %d %d | %d %d | %d %d\n", my->pos.x, my->pos.y, (int) my->canUse(AirborneSkill), buildablePos.size(), freeEnergy, Skill::Cost(AirborneSkill, my->level, my->type));
				//优先空投
				if(my->canUse(AirborneSkill) && buildablePos.size()
					&& freeEnergy >= Skill::Cost(AirborneSkill, my->level, my->type)
				&& value(buildablePos.front()) >= 20)
				{
					// printf("use Airborne!\n");
					pCommand.AddOrder(Airborne, my->pos, buildablePos.front(), 0);
					occupied.push_back(buildablePos.front());
					buildablePos.erase(buildablePos.begin());
					sort(buildablePos.begin(), buildablePos.end(), cmpEmpty);
					need[my->pos] += Skill::Cost(AirborneSkill, my->level, my->type);
					goto usedSkill;
				}
				//如果我是采集型（或啥都不是），我就想进化
				//采集型不要进化太多
				if((my->type == GatherRobot || my->type == RawRobot) && my->canUse(EvolveSkill)
					&& freeEnergy >= Skill::Cost(EvolveSkill, my->level, my->type) && my->level <= 1)
				{
					// printf("use Evolve!\n");
					pCommand.AddOrder(Evolve, my->pos, my->type == RawRobot ? GatherRobot : my->type);
					need[my->pos] += Skill::Cost(EvolveSkill, my->level, my->type);
					goto usedSkill;
				}
				//如果我是其他类型，我就想变成采集型
				if(my->type != GatherRobot && my->type != RawRobot && my->canUse(VestigialSkill)
					&& freeEnergy >= Skill::Cost(VestigialSkill, my->level, my->type))
				{
					// printf("use Vestigial!\n");
					pCommand.AddOrder(Vestigial, my->pos, GatherRobot);
					need[my->pos] += Skill::Cost(VestigialSkill, my->level, my->type);
					goto usedSkill;
				}
				//如果不能空投，可以选择分裂
				if(freeEnergy >= Skill::Cost(SplitSkill, my->level, my->type) && buildablePos.size())
				{
					// printf("use SplitSkill!\n");
					for(int i = 0; i < buildablePos.size(); i++)
						if(my->pos.dist2(buildablePos[i]) <= SplitRange && value(buildablePos[i]) >= 20){
							pCommand.AddOrder(Split, my->pos, buildablePos[i]);
							occupied.push_back(buildablePos[i]);
							buildablePos.erase(buildablePos.begin() + i);
							sort(buildablePos.begin(), buildablePos.end(), cmpEmpty);
							need[my->pos] += Skill::Cost(SplitSkill, my->level, my->type);
							goto usedSkill;
						}
				}
				// printf("use noSkill!\n");
				//没什么重大技能要用了，可以没事做一点连接
				if(my->canUse(ConnectSkill) && freeEnergy >= Skill::Cost(ConnectSkill, my->level, my->type))
				{
					//先寻找连接目标，优先连中间，然后后方，最后前方（但是估计也连不上）
					//并且，优先连接较强壮的友方
					vector<const Robot *> targets;
					targets.insert(targets.end(), myMiddle.rbegin(), myMiddle.rend());
					targets.insert(targets.end(), myBack.rbegin(), myBack.rend());
					targets.insert(targets.end(), myFront.rbegin(), myFront.rend());
					for(auto target: targets)
						if(my->pos.dist2(target->pos) <= SplitRange && !links.count(make_pair(my->pos, target->pos)))
						{
							pCommand.AddOrder(Connect, my->pos, target->pos);
							need[my->pos] += Skill::Cost(ConnectSkill, my->level, my->type);
							goto usedSkill;
						}
				}
			}
		}
		usedSkill:;
	}
	//技能都用完了，可以进行传输了
	// printf("trans begin\n");
	pCommand.AddAutoTransfer(playerInfo, weight, need);
	// printf("trans end\n");
}
}

//普通AI接口，一回合调用一次
extern "C"
{
EXPORT void player_ai(const PlayerInfo &playerInfo_, Commands &pCommand_, PShowInfo &pShowInfo_) {
    //这里将传入的PlayerInfo转化为PPlayerInfo格式
	// printf("ai begin\n");
	playerInfo = SDK::interpretPlayerInfo(playerInfo_);
    pShowInfo = &pShowInfo_;
    DecentAI0::solve();
    //cout << "target: " << target.x << ',' << target.y << '\n';	pCommand.AddAutoTransfer(playerInfo, target);//能量调度
    // pCommand.AddAutoTransfer(playerInfo, target);//能量调度
	pCommand_ = SDK::translateCommands(playerInfo, pCommand);
	// printf("ai end\n");
}
}
